package com.dzjcloud.dzj.upms.biz.controller;

import cn.dev33.satoken.annotation.SaIgnore;
import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.LineCaptcha;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.crypto.SecureUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.dzjcloud.dzj.common.core.enums.ResultEnum;
import com.dzjcloud.dzj.common.core.exception.HandleException;
import com.dzjcloud.dzj.common.core.utils.R;
import com.dzjcloud.dzj.common.core.utils.RequestIpUtils;
import com.dzjcloud.dzj.common.redis.utils.RedisUtil;
import com.dzjcloud.dzj.upms.api.dto.VerificationCheckDto;
import com.dzjcloud.dzj.upms.api.entity.User;
import com.dzjcloud.dzj.upms.api.form.doLoginForm;
import com.dzjcloud.dzj.upms.biz.service.UserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.util.Set;

/**
 * <h3>dzj-cloud</h3>
 * <p>登录前端控制器</p>
 *
 * @author : DongZeJian
 * @date : 2021-05-25 16:25
 **/
@RestController
@Api(tags = "登录前端控制器",value = "登录前端控制器")
@RequestMapping
@Slf4j
@Validated
@RequiredArgsConstructor
public class LoginController {

    private final RedisUtil redisUtil;

    private final UserService userService;

    @Getter
    @Setter
    @Value("${sa-token.timeout}")
    private Long timeout;

    @ApiOperation("获取验证码")
    @GetMapping("/verification/open")
    @SaIgnore
    public void verificationCode(HttpServletResponse response) throws IOException {
        //此参数 可以改为 随机验证码
        String ipAddr = RequestIpUtils.getIpAddr();
        //生成验证码
        LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(200, 100);
        //验证码存入redis
        VerificationCheckDto verificationCheckDto= JSON.parseObject((String)redisUtil.get(ipAddr), VerificationCheckDto.class);
        if (ObjectUtil.isNull(verificationCheckDto)) {
            redisUtil.set(ipAddr, JSON.toJSONString(new VerificationCheckDto(lineCaptcha.getCode(),1)), 300);
        } else {
            verificationCheckDto.setVerificationCode(lineCaptcha.getCode());
            redisUtil.set(ipAddr,JSON.toJSONString(verificationCheckDto),300);
        }
        //验证码图片输出到前端
        response.setContentType("image/jpeg");
        response.setHeader("Content-Disposition","attachment;filename=verificationCode.png");
        //设置响应头
        response.setHeader("Pragma", "no-cache");
        //设置响应头
        response.setHeader("Cache-Control", "no-cache");
        //在代理服务器端防止缓冲
        response.setDateHeader("Expires", 0);

        //输出验证码图片
        lineCaptcha.write(response.getOutputStream());
        response.getOutputStream().flush();
    }

    @PostMapping("/doLogin")
    @ApiOperation("登录")
    public R<SaTokenInfo> doLogin(@RequestBody @Valid doLoginForm form){
        String ipAddr = RequestIpUtils.getIpAddr();
        //校验登录次数
        VerificationCheckDto verificationCheckDto = Validator.validateNotNull(JSON.parseObject((String)redisUtil.get(ipAddr), VerificationCheckDto.class), "先请求验证码");
        if (verificationCheckDto.getCount()>5){
            throw new HandleException(ResultEnum.ERROR_CODE.getCode(),"登录失败过多，请稍后再试");
        } else{
            verificationCheckDto.setCount(verificationCheckDto.getCount()+1);
            redisUtil.set(ipAddr,JSON.toJSONString(verificationCheckDto),300);
        }

        //校验验证码
        Validator.validateEqual(form.getVerification(),verificationCheckDto.getVerificationCode(),"验证不正确");

        //校验账号密码
        User user = Validator.validateNotNull(userService.getOne(Wrappers.<User>lambdaQuery().eq(User::getUserCode, form.getUserName())), "用户不存在");
        Validator.validateEqual(user.getPasswrod(), SecureUtil.md5(form.getPassword()),"密码不正确");

        //以上验证通过删除验证码
        redisUtil.del(ipAddr);

        //satoken 登录
        StpUtil.login(user.getId(),form.getRemember());


        //如果之前登录的缓存用户信息还在先删除
        Set<String> keys = redisUtil.keys("*" + StpUtil.getLoginId() + "*");
        for (String key : keys) {
            redisUtil.del(key);
        }
        //登录成功后存一份用户信息在 redis
        redisUtil.set(StpUtil.getTokenValue()+StpUtil.getLoginId(),JSON.toJSONString(user),timeout);

        return R.ok(StpUtil.getTokenInfo());
    }



    @GetMapping("/logout")
    @ApiOperation("注销")
    public R<String> logout(){
        StpUtil.logout();
        return R.ok("注销成功");
    }
}
